require('../../models/workspace.js');
require('../../models/build_cfg.js');
require('../../models/member.js');
require('../../models/publish_cfg.js');
require('../../models/build_cfg.js');
require('../../models/build.js');
require('../../models/product_cfg.js');


var _ = require('lodash');
var ProjectProxy = require('../../proxy/project.js');
var MemberProxy = require('../../proxy/member.js');
var workspaceAPI = require('./workspace');
var mongoose = require('mongoose');
var Project = mongoose.model('Project');
var Member = mongoose.model('Member');
var Workspace = mongoose.model('Workspace');
var BuildConfig = mongoose.model('BuildConfig');
var Build = mongoose.model('Build');
var ProductConfig = mongoose.model('ProductConfig');
var PublishConfig = mongoose.model('PublishConfig');
var config = require('../../config.json');
var tools = require('../../common/tools.js');
var xml2js = require('xml2js');
var X2JPaser = new xml2js.Parser();
var path = require('path');
var fs = require('fs');
var builder = new xml2js.Builder();

var logger = require('log4js').getLogger();
var EventProxy = require('eventproxy');
var waterfall = require('async-waterfall');
var simpleGit = require('simple-git')(config.workspace.gitolite.gitolite_repo);
var removeDir = require('../../common/removeDir.js');
var request = require('request');
//var createGitRepository = require('./workspace/gitoper.js').createGitRepository;


exports.getCurrentProject = function (req, res, next) {
    var cur_project = req.cookies.cur_project;
    var user = req.query.user;
    var role = "all";
    var projects_info = [];
    var ep = new EventProxy();
    ep.fail(function (err) {
        return res.format_json(null, 500, err);
    });
    ep.on("no_project_cookie",function(){
        MemberProxy.getProjects(user, role, function (err, data) {
            if (err) {
                return res.format_json({}, 500, err);
            }
            if (data.length > 0) {
                ep.after('projects_info_found', data.length, function () {
                    res.cookie("cur_project", data[0]._id, {maxAge: 36000000});
                    res.format_json(projects_info[0], 0);
                });

                data.map(function (info) {
                    Project.findOne({'_id': info.projectId}, function (error, project) {
                        if (error) {
                            return res.format_json({}, 500, error);
                        }
                        projects_info.push(project);
                        ep.emit('projects_info_found');
                    });
                });
            } else {
                res.format_json({}, 0);
            }
        });

    });
    if(cur_project!='undefined' && typeof(cur_project) == "string"){
        MemberProxy.getMembers(cur_project,function(err,data){
            if(err){
                return res.format_json(null, 500, err);
            }else{
                var index = _.findIndex(data,{user:user});
                if(index >= 0){
                    Project.findOne({'_id': cur_project}, function (error, project) {
                        if (error) {
                            ep.emit("no_project_cookie");
                            //return res.format_json({}, 500, error);
                        }else if(project){
                            return res.format_json(project, 0);
                        }else{
                            ep.emit("no_project_cookie");
                        }

                    });
                }else{
                    ep.emit("no_project_cookie");
                }
            }
        })
    }else{
        ep.emit("no_project_cookie");
    }

};

exports.getList = function (req, res, next) {
    var user = req.query.user;
    var role = req.query.role;

    MemberProxy.getProjects(user, role, function (err, data) {
        if (err) {
            return res.format_json({}, 500, err);
        }
        var ep = new EventProxy();
        var projects = [];
        ep.fail(function (err) {
            res.format_json(null, 500, err);
        });
        ep.after('projects_info_found', data.length, function () {
            //res.cookie("cur_project",projects[0],{ maxAge: 900000 });
            res.format_json(projects, 0);
        });

        data.map(function (info) {
            Project.findOne({'_id': info.projectId}, function (error, project) {
                if (error) {
                    return res.format_json(null, 500, error);
                }
                projects.push(project);
                ep.emit('projects_info_found');
            });
        });
    });
};
//exports.getByName = function(req, res, next){
//    var name = req.params.name;
//    // get projectList
//    res.json({data:{}});
//};


/**
 * 根据project _id 获取project信息
 * @param req
 * @param res
 * @param next
 */
exports.getById = function (req, res, next) {

    var project_id = req.params.project_id;
    ProjectProxy.getProjectById(project_id, function (err, data) {
        if (err) {
            res.clearCookie("cur_project");
            return res.format_json(null, 500, err);
        }
        res.cookie("cur_project", data._id, {maxAge: 36000000});
        res.format_json(data, 0);
    });
};
/**
 * 创建项目：
 * 1. 数据库中添加新建项目数据
 * 2. member中添加数据
 * 3. 为项目创建git库（包括master分支和develop分支，直接使用自己的git服务）
 * 4. 为项目创建master_workspace（clone master分支）
 * 5. 在这个过程中失败的话，提供回滚：删除项目数据，成员数据，git库，master_workspace
 * TODO::如果支持第三方git库，这里创建git库的过程需要变化
 *
 * @param req
 * @param res
 * @param next
 */
exports.addProject = function (req, res, next) {

    var projectInfo = req.body;
    var user = req.session.user.shortid;
    projectInfo['creator'] = user;
    var ep = new EventProxy();
    ep.fail(function (err) {
        return res.format_json(null, 500, err);
    });
    var project = {};
    ProjectProxy.addProject(projectInfo, function(err,data){
        if(err){
            return res.format_json(null, 500, err.errmsg);
        }
        project = data;
        ep.emit('project_added');
    });

    ep.on('project_added', function () {
        MemberProxy.addMember({
            'projectId': project._id,
            'projectTitle': project.title,
            'user': user,
            'role': 'owner'
        }, function () {
            ep.emit('member_added');
        });
    });

    ep.on('member_added', function () {
        create_wkp_dirs(project, function (err) {
            if (err) {
                create_project_error_rollback(project, function (error) {
                    if (error) {
                        logger.error("项目创建失败:master workspace 目录创建失败，回滚失败");
                        return res.format_json(null, 500, error);
                    } else {
                        logger.info("项目创建失败:master workspace 目录创建失败，回滚成功");
                        return res.format_json(null, 500, "项目创建失败");
                    }
                });
            } else {
                ep.emit('master_workspace_dirs_created');
            }
        });

    });

    ep.on('master_workspace_dirs_created', function () {
        createGitRepository(project, function (err) {
            if (err) {
                create_project_error_rollback(project, function (error) {
                    if (error) {
                        logger.error("项目创建失败:git clone失败，回滚失败");
                        return res.format_json(null, 500, error);
                    } else {
                        logger.info("项目创建失败:git clone失败，回滚成功");
                        return res.format_json(null, 500, "项目创建失败");
                    }
                })
            } else {
                logger.info("项目创建完成");
                res.format_json({success: true, project: project});
            }
        });

    });

};

exports.pushCert = function (req, res, next) {
    var body = req.body;
    var cert_id = body.cert_id;
    var project_id = body.project_id;
    ProjectProxy.pushProCert(project_id, cert_id, function (err, data) {
        if (err) {
            return res.format_json(null, 500, "添加证书失败:" + err);
        }
        res.format_json(data);
    })
};

exports.removeCert = function (req, res, next) {
    var body = req.body;
    var cert_id = body.cert_id;
    var project_id = body.project_id;
    ProjectProxy.removeProCert(project_id, cert_id, function (err, data) {
        if (err) {
            return res.format_json(null, 500, "删除证书失败:" + err);
        }
        res.format_json(data);
    })
};

exports.addDependency = function (req, res, next) {
    var dependency_info = req.body;
    var project_id = req.params.project_id;
    ProjectProxy.addDependency(project_id, dependency_info, function (err, data) {
        if (err) {
            return res.format_json(null, 500, "添加依赖失败:" + err);
        }
        res.format_json(data);
    })
};

exports.removeDependency = function (req, res, next) {
    var dependency_info = req.body;
    var project_id = req.params.project_id;
    ProjectProxy.removeDependency(project_id, dependency_info, function (err, data) {
        if (err) {
            return res.format_json(null, 500, "删除依赖失败:" + err);
        }
        res.format_json(data);
    })
};

exports.updateDependency = function (req, res, next) {
    var dependency_info = req.body;
    var project_id = req.params.project_id;
    ProjectProxy.updateDependency(project_id, dependency_info, function (err, data) {
        if (err) {
            return res.format_json(null, 500, "更新依赖失败:" + err);
        }
        res.format_json(data);
    })
};

exports.updateDependencies = function (req, res, next) {
    var dependencies = req.body;
    var project_id = req.params.project_id;
    ProjectProxy.updateDependencies(project_id, dependencies, function (err, data) {
        if (err) {
            return res.format_json(null, 500, "更新依赖失败:" + err);
        }
        res.format_json(data);
    })
};
exports.getAllProjects = function (req, res, next) {

    ProjectProxy.getAllProjects(function (err, data) {
        if (err) {
            return res.format_json({}, 500, err);
        }
        res.format_json(data, 0);
    });
};

//exports.testQuery = function(req, res, next){
//    ProjectProxy.testQuery(function (err, data) {
//        if (err) {
//            return res.format_json({}, 500, err);
//        }
//        res.format_json(data, 0);
//    });
//};
exports.updateProject = function (req, res, next) {
    var project_id = req.params.project_id;
    var update_info = req.body;
    ProjectProxy.updateProject(project_id, update_info, function (err, data) {
        if (err) {
            return res.format_json({}, 500, err);
        }
        res.format_json(data, 200);
    });

};
exports.deleteProject = function (req, res, next) {
    //删除项目相关内容：project，member，workspace，buildConfigs，builds，productConfig,publishConfig
    var project_id = req.params.project_id;
    var cur_project = req.cookies.cur_project;
    var workspace;
    var project;
    if (cur_project && cur_project._id == project_id) {
        res.clearCookie("cur_project");
    }


    var ep = new EventProxy();
    //先删除文件和git_repo 之后再删除project workspace 然后其他
    ep.all('wkp_del', 'git_del', function () {
        remove_data();
    });

    ep.on('del_wkp_error', function () {
        return res.format_json(null, 500, '删除工作空间失败');
    });
    ep.on('space_error', function () {
        return res.format_json(null, 500, '工作空间配置失败');
    });

    delete_git_rep();
    ProjectProxy.getProjectById(project_id, function (err, data) {

        if (err) {
            return res.format_json(null, 500, '删除工作空间失败');
        }
        project = data;
        Workspace.find({project_id: project._id}, function (err, docs) {
            if (err) {
                logger.error('get workspace of porject ' + project_id + 'error');
                return res.format_json(null, 500, 'get workspace of porject ' + project_id + 'error');
            } else if (docs && docs.length > 0 ) {
                ep.after("delete_wkp",docs.length,function(){
                    //delete project_dir in workspaces and master_workspaces
                    var project_dir_in_workspaces = path.join(config.workspace.workspeces_path,project.namespace,project.name);
                    var project_dir_in_master_workspaces = path.join(config.master_workspaces,project.namespace,project.name);
                    try{
                        logger.info("delete project_dir in workspaces and master_workspaces");
                        fs.rmdirSync(project_dir_in_workspaces);
                        tools.rmdirAllSync(project_dir_in_master_workspaces);
                        ep.emit('wkp_del');
                    }catch(e){
                        logger.error("delete project_dir in workspaces and master_workspaces error");
                        logger.error(e);
                        return res.format_json(null, 500, 'delete project_dir in workspaces and master_workspaces error');
                    }

                });
                docs.forEach(function(doc){
                    delete_wkp(doc._doc,project);
                });
            } else {
                logger.info('porject: ' + project_id + ' has no workspace');
                ep.emit('wkp_del');

            }
        });
    });


    function delete_git_rep() {
        Project.findOne({_id: project_id}, function (err, doc) {
            if (doc) {
                workspaceAPI.removeGit(doc._doc.namespace+ '/' +doc._doc.name, function (err, data) {
                    if (data === 'done') {
                        logger.info('git_repo: "' + doc._doc.namespace+ '/' +doc._doc.name + '" deleted!');
                        ep.emit('git_del');
                    } else {
                        logger.error('delete git_repo: "' + doc._doc.namespace+ '/' +doc._doc.name + '"occurs error !');
                        return res.format_json(null, 500, 'delete git_repo: "' + doc._doc.namespace+ + '/' + doc._doc.name + '"occurs error !');
                    }
                });
            } else {
                logger.error('get project by id:' + project_id + 'occurs error!');
                return res.format_json(null, 500, 'get project by id:' + project_id + 'occurs error!');
            }
        });
    }

    function delete_wkp(workspace,project) {
        var workspace_name = workspace.work_name;
        var root = config.workspace.workspeces_path;
        var namespace_path = path.join(root, project.namespace);
        var project_dir = path.join(namespace_path,project.name);
        var wkp_path = path.join(project_dir, workspace_name);
        var filename = path.join(config.workspace.workspeces_path, config.workspace.space);

        try {
            fs.accessSync(wkp_path, fs.R_OK);
            delete_workspace(filename, workspace, wkp_path);
        } catch (e) {
            logger.info('workspace' + wkp_path + ' not exist');
            ep.emit('delete_wkp');
        }
    }

    function delete_workspace(filename, workspace, wkp_path) {
        try {
            tools.rmdirAllSync(wkp_path);
        } catch (e) {
            logger.error('remove workspace ' + wkp_path + 'error');
            ep.emit('del_wkp_error');
        }
        fs.readFile(filename, 'utf-8', function (err, data) {
            if (err) {
                logger.error('read space.xml failed');
                ep.emit('space_error');
            }
            X2JPaser.parseString(data, function (err, result) {
                var array = result.workspaces.workspace;
                if (typeof(result.workspaces.workspace) == 'undefined') {
                    logger.error("space.xml不存在");
                    ep.emit('space_error');
                } else {
                    for (var i = 0; i < array.length; i++) {
                        var work = array[i];
                        if (work.$.id == workspace.work_name) {
                            array.splice(i, 1);
                        }
                    }
                    if (array.length == 0) {
                        result.workspaces = {
                            '$': {
                                name: "workspaces",
                            }
                        };
                    } else {
                        result.workspaces.workspace = array;
                    }
                    var xmlString = builder.buildObject(result);
                    fs.writeFile(filename, xmlString, 'utf-8', function (err) {
                        if (err) {
                            logger.error("space.xml重写失败");
                            ep.emit('space_error');
                        }
                        logger.info('workspace: "' + workspace.work_name + '" deleted!');
                        ep.emit('delete_wkp');
                    });
                }
            });
        })
    }

    function remove_data() {
        //删除数据库数据
        Project.remove({'_id': project_id}, function (error) {
            if (error) {
                logger.error("删除项目信息失败");
                return res.format_json(null, 500, error);
            }
            Workspace.remove({'project_id': project_id}, function (error) {
                if (error) {
                    logger.error("删除工作空间信息失败");
                    return res.format_json(null, 500, error);
                }

                Member.remove({'projectId': project_id}, function (error) {
                    if (error) {
                        logger.error("删除成员信息失败");
                        return res.format_json(null, 500, error);
                    }
                });

                BuildConfig.remove({'project': project_id}, function (error) {
                    if (error) {
                        logger.error("删除构建配置信息失败");
                        return res.format_json(null, 500, error);
                    }
                });
                Build.remove({'project': project_id}, function (error) {
                    if (error) {
                        logger.error("删除构建信息失败");
                        return res.format_json(null, 500, error);
                    }
                });
                ProductConfig.remove({'project': project_id}, function (error) {
                    if (error) {
                        logger.error("删除产品配置信息失败");
                        return res.format_json(null, 500, error);
                    }
                });
                PublishConfig.remove({'project': project_id}, function (error) {
                    if (error) {
                        return res.format_json(null, 500, error);
                    }
                });
                logger.info("删除项目成功");
                return res.format_json({}, 200);
            });
        });
    }


};

/**
 * 项目创建失败时信息回滚：删除项目数据，成员数据，git库，master_workspace
 * @param project_info （包含project._id project.name）
 * @param callback
 */
function create_project_error_rollback(project_info, callback) {
    var ep = new EventProxy();
    ep.fail(callback);

    Project.remove({'_id': project_info._id}, function (error) {
        if (error) {
            logger.err(error);
            logger.error("项目" + project_info.name + "创建失败信息回滚错误：删除项目信息失败");
            callback("项目创建失败信息回滚错误：删除项目信息失败");
        } else {
            Member.remove({'projectId': project_info._id}, function (error) {
                if (error) {
                    logger.err(error);
                    logger.error("项目" + project_info.name + "创建失败信息回滚错误：删除项目相关成员信息失败");
                    callback("项目创建失败信息回滚错误：删除项目相关成员信息失败");
                } else {
                    ep.emit("member_rec_deleted");
                }
            });
        }
    });
    ep.on("member_rec_deleted", function () {
        var removeGit = require('./workspace/gitoper.js').removeGit;
        removeGit(project_info.namespace + '/' +project_info.name, function (err, data) {
            if (data === 'done') {
                logger.info('git_repo: "' + project_info.name + '" deleted!');
                ep.emit('git_deleted');
            } else {
                logger.error(err);
                logger.error("项目" + project_info.name + "创建失败信息回滚错误：删除git失败");
                callback("项目创建失败信息回滚错误：删除git失败");
            }
        });
    });

    ep.on('git_deleted', function () {
        var rmdirAllSync = require('../../common/tools.js').rmdirAllSync;
        var master_wkp = path.join(config.master_workspaces, project_info.namespace,project_info.name);
        try {
            fs.accessSync(master_wkp, fs.R_OK);
            rmdirAllSync(master_wkp);
            callback(null);
        } catch (e) {
            logger.info(master_wkp + ' not exist');
            callback(null);
        }
    })

}
exports.createGitRepository = createGitRepository;
function createGitRepository(project, call_back) {
    var workspace_dirs = require('./workspace/dirs.js').workspace_dirs;
    var repoPath = config.workspace.gitolite.repo_pre + project.namespace+ '/' + project.name;
    var localPath = path.join(config.master_workspaces,project.namespace,
        project.name, workspace_dirs.Source, project.name);
    var ignore_path = path.join(localPath, ".gitignore");
    var git_server = "http://"+config.git_server.host+":"+config.git_server.port+"/api/git/create";

    waterfall([
        //1.调用git-server创建git库
        function (cb) {
            request.post({url:git_server,
                form: {project_name:project.namespace+ '/' + project.name}}, function(err,req){
                if(err){
                    logger.error(err);
                    logger.error("调用git服务出错");
                    return call_back(err);
                }
                if(req.body.code == "500"){
                    logger.error(res.msg);
                    return call_back(res.msg);
                }
                logger.info("git服务创建git库成功");
                cb(null);
            });
        },
        //2.clone项目
        function (cb) {
            fs.exists(localPath, function (exists) {
                if (exists) {
                    removeDir.remove(localPath, function (err) {
                        if (err) {
                            logger.info("删除原目录失败");
                        }
                        simpleGit.clone(repoPath, localPath, function (err, data) {
                            if (err) {
                                logger.error(err);
                                logger.error("clone项目失败");
                                return call_back(err);
                            }
                            logger.info("clone项目成功");
                            cb(null);
                        });
                    });
                }else{
                    simpleGit.clone(repoPath, localPath, function (err, data) {
                        if (err) {
                            logger.error(err);
                            logger.error("clone项目失败");
                            return call_back(err);
                        }
                        logger.info("clone项目成功");
                        cb(null);
                    });
                }
            });
        },
        function (cb) {
            fs.writeFile(ignore_path, "*/jmx/*\r\n*.class", 'utf-8', function (err) {
                if (err) {
                    logger.error(err);
                    logger.error("创建.gitignore文件出错");
                    return call_back(err);
                }
                logger.info("创建.gitignore文件成功");
                cb(null);
            });
        },
        function (cb) {
            require('simple-git')(localPath)
                .add('./.gitignore')
                .commit("first commit!")
                .push('origin', 'master', function (err, data) {
                    if (err) {
                        logger.error(err);
                        logger.error("推送.gitignore出错");
                        return call_back(err);
                    }
                    logger.info("推送.gitignore成功");
                }).checkoutLocalBranch('develop', function (err, result) {
                if (err) {
                    logger.error(err);
                    logger.error("切换develop失败");
                    return call_back(err);
                }
                logger.info("切换develop成功");
            }).push('origin', 'develop', function (err, data) {
                if (err) {
                    logger.error(err);
                    logger.error("推送develop分支出错");
                    return call_back(err);
                }
                logger.info("推送develop成功");
            }).checkout('master', function (err, result) {
                if (err) {
                    logger.error(err);
                    logger.error("切回master失败");
                    return call_back(err);
                }
                logger.info("切回master成功");
                cb(null);
            });
        }
    ], function (err, result) {
        if (err) {
            logger.error(err);
            return call_back("未知的异常，创建git库失败");
        }
        call_back(null, "done");
    });
}
exports.create_wkp_dirs = create_wkp_dirs;
function create_wkp_dirs(project_info, callback) {
    var ep = new EventProxy();
    ep.fail(callback);
    ep.on("master_workspace_created",callback);

    var dirs = require('./workspace/dirs.js').getDirs();
    var root = config.master_workspaces;
    var namespace_dir = path.join(root,project_info.namespace);
    var full_path = path.join(namespace_dir,project_info.name);
    fs.access(root,function(err){
        if(err){
            fs.mkdirSync(root);
        }
        fs.access(namespace_dir,function(err){
            if(err){
                fs.mkdirSync(namespace_dir);
            }
            try {
                fs.accessSync(full_path, fs.R_OK);
                removeDir.remove(full_path, function (err) {
                    if (err) {
                        logger.error("删除原目录失败");
                        return callback("删除原目录失败");
                    }
                    fs.mkdirSync(full_path);
                    dirs.map(function (dir, i) {
                        fs.mkdirSync(path.join(full_path, dir));
                    });
                    logger.info("master_workspace 目录创建成功");
                    ep.emit("master_workspace_created");
                });

            } catch (e) {
                fs.mkdirSync(full_path);
                dirs.map(function (dir, i) {
                    fs.mkdirSync(path.join(full_path, dir));
                });
                logger.info("master_workspace 目录创建成功");
                ep.emit("master_workspace_created");
            }
        })
    });
}
